/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		errordialog.cpp
 * PURPOSE:		custom resiziable dialog box shown when an error occurs
 *				used to replace MessageBox with its ambiguous buttons and non-selectable text
 */

namespace ErrorDialog
{

class WindowObject : public DialogWindowBase
{
	RECT OrigWindowSize;
	RECT OrigTextRect;
	RECT OrigAbortRect;
	RECT OrigRetryRect;
	RECT OrigIgnoreRect;

	PCWSTR ErrorTitle;
	PCWSTR ErrorText;
	BOOLEAN Noncontinuable;
	BOOLEAN CanCancel;

public:
	WindowObject(HWND Parent, PCWSTR ErrorTitle, PCWSTR ErrorText, BOOLEAN Noncontinuable, BOOLEAN CanCancel, int &Result) :
		ErrorTitle(ErrorTitle),
		ErrorText(ErrorText),
		Noncontinuable(Noncontinuable),
		CanCancel(CanCancel)
	{
		inc_ref(); //for thread
		Result = static_cast<int>(CreateModal(SdEditGModule, MAKEINTRESOURCE(IDD_ERROR), Parent));
		dec_ref();
	}

	static void ScreenRectToClientRect(HWND Wnd, RECT *Rect)
	{
		POINT P1 = {Rect->left, Rect->top};
		POINT P2 = {Rect->right, Rect->bottom};

		ScreenToClient(Wnd, &P1);
		ScreenToClient(Wnd, &P2);

		Rect->left = P1.x;
		Rect->top = P1.y;
		Rect->right = P2.x;
		Rect->bottom = P2.y;
	}

	static void ClientRectToScreenRect(HWND Wnd, RECT *Rect)
	{
		POINT P1 = {Rect->left, Rect->top};
		POINT P2 = {Rect->right, Rect->bottom};

		ClientToScreen(Wnd, &P1);
		ClientToScreen(Wnd, &P2);

		Rect->left = P1.x;
		Rect->top = P1.y;
		Rect->right = P2.x;
		Rect->bottom = P2.y;
	}

	void MoveItemWindowRect(int id, RECT const *Rect, int xdiff, int ydiff)
	{
		MoveWindow(GetDlgItem(Wnd, id), Rect->left + xdiff, Rect->top + ydiff, Rect->right - Rect->left, Rect->bottom - Rect->top, FALSE);
	}

	void GetDialogClientRect(int id, RECT *Rect)
	{
		HWND ItemWnd = GetDlgItem(Wnd, id);

		GetWindowRect(ItemWnd, Rect);
		ScreenRectToClientRect(Wnd, Rect);
	}

	void InitDialog()
	{
		GetClientRect(Wnd, &OrigWindowSize);

		GetDialogClientRect(IDC_TEXT, &OrigTextRect);
		GetDialogClientRect(IDABORT, &OrigAbortRect);
		GetDialogClientRect(IDRETRY, &OrigRetryRect);
		GetDialogClientRect(IDIGNORE, &OrigIgnoreRect);

		SetWindowText(Wnd, ErrorTitle);
		SetWindowText(GetDlgItem(Wnd, IDC_TEXT), ErrorText);

		if(Noncontinuable)
			ShowWindow(GetDlgItem(Wnd, IDRETRY), SW_HIDE);

		if(!CanCancel)
			ShowWindow(GetDlgItem(Wnd, IDIGNORE), SW_HIDE);
	}

	void SetDimensions(RECT *rect)
	{
		ScreenRectToClientRect(Wnd, rect);

		rect->right = max(rect->right, OrigWindowSize.right);
		rect->bottom = max(rect->bottom, OrigWindowSize.bottom);

		int xdiff = rect->right - OrigWindowSize.right;
		int ydiff = rect->bottom - OrigWindowSize.bottom;

		MoveWindow(GetDlgItem(Wnd, IDC_TEXT), OrigTextRect.left, OrigTextRect.top, OrigTextRect.right - OrigTextRect.left + xdiff, OrigTextRect.bottom - OrigTextRect.top + ydiff, FALSE);

		MoveItemWindowRect(IDABORT, &OrigAbortRect, xdiff, ydiff);
		MoveItemWindowRect(IDRETRY, &OrigRetryRect, xdiff, ydiff);
		MoveItemWindowRect(IDIGNORE, &OrigIgnoreRect, xdiff, ydiff);

		ClientRectToScreenRect(Wnd, rect);

		RedrawWindow(Wnd, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
	}

	virtual LRESULT RecieveMessage(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) override
	{
		switch(msg)
		{
		case WM_SIZING:
			SetDimensions(reinterpret_cast<RECT *>(lparam));
			return TRUE;

		case WM_INITDIALOG:
			InitDialog();
			return TRUE; //value ignored, but the presence of SOME value means dlgproc will return TRUE

		case WM_COMMAND:
			if(HIWORD(wparam) == BN_CLICKED) //notification code
				if(LOWORD(wparam) != IDCANCEL) //no cancel button
					EndDialog(Wnd, LOWORD(wparam)); //control id
			break;
		}

		return __super::RecieveMessage(wnd, msg, wparam, lparam);
	}
};

int CALLBACK ShowErrorMessageBox(PCWSTR Title, PCWSTR Text, HWND Parent, BOOLEAN Noncontinuable, BOOLEAN CanCancel)
{
	int Result = 0;

	new WindowObject(Parent, Title, Text, Noncontinuable, CanCancel, Result); //object will be deleted by the time it's finished, since its modal

	return Result;
}

}//namespace ErrorDialog